﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Globalization;

using Microsoft.SharePoint;

namespace ListItemEditor
{
    public class GridViewDataSourceSPQueryCustom : GridViewDataSourceSPQuery
    {
        private delegate object GetListItemValue(SPListItem item, SPField field);

        private class FieldData
        {
            public string FieldName { get; set; }
            public Type ColumnType { get; set; }
            public GetListItemValue GetListItemValue { get; set; }
            public SPField Field { get; set; }
        }

        private static Dictionary<Type, GetListItemValue> _getListItemValueMap = new Dictionary<Type, GetListItemValue>()
        {
            { typeof(bool), GetFieldValueBoolean },
            { typeof(int), GetFieldValueInt },
            { typeof(double), GetFieldValueDouble },
            { typeof(DateTime), GetFieldValueDateTime },
            { typeof(string), GetFieldValueString },
        };

        protected override DataTable GetDataTableFromItems(SPListItemCollection items)
        {
            List<FieldData> datas = GetFieldDatas(items.List);
            DataTable table = new DataTable();
            table.TableName = items.List.Title;

            table.Columns.AddRange (
                    datas.Select(d => new DataColumn(d.FieldName, d.ColumnType)).ToArray() );

            foreach (SPListItem item in items)
            {
                DataRow row = table.NewRow();
                row.ItemArray = datas.Select(d => d.GetListItemValue(item, d.Field)).ToArray();
                table.Rows.Add(row);
            }

            return table;
        }

        private List<FieldData> GetFieldDatas(SPList list)
        {
            List<FieldData> datas = new List<FieldData>();

            foreach (string fieldName in this.GetEffectiveViewFields(list is SPDocumentLibrary))
            {
                // survey list doesn't contain Attachments
                if (!list.Fields.ContainsField(fieldName)) continue;

                SPField field = list.Fields.GetFieldByInternalName(fieldName);

                Type columnType = GetColumnTypeFromFieldType(field);
                if (columnType == typeof(string)) columnType = GetColumnTypeFromFieldValueType(field);

                FieldData data = new FieldData() { ColumnType = columnType, Field = field, FieldName = field.InternalName, GetListItemValue = _getListItemValueMap[columnType] };
#if SHAREPOINT2010
                // didn't want to reference the Taxonomy assembly directly
                if (field.GetType().Name.Equals("TaxonomyField")) data.GetListItemValue = GetFieldValuTaxonomy;
#endif
                datas.Add(data);
            }
            return datas;
        }

        private Type GetColumnTypeFromFieldValueType(SPField field)
        {
            Type fieldValueType = field.FieldValueType;
            if (fieldValueType == typeof(bool) || fieldValueType == typeof(int) || fieldValueType == typeof(double) || fieldValueType == typeof(DateTime)) return fieldValueType;
            return typeof(string);
        }

        private Type GetColumnTypeFromFieldType(SPField field)
        {
            switch (field.Type)
            {
                case SPFieldType.Integer:
                case SPFieldType.Counter:
                    return typeof(int);

                case SPFieldType.Boolean:
                case SPFieldType.Attachments:
                case SPFieldType.Recurrence:
                case SPFieldType.CrossProjectLink:
                    return typeof(bool);

                case SPFieldType.DateTime:
                    return typeof(DateTime);

                case SPFieldType.Number:
                case SPFieldType.Currency:
                    return typeof(double);
                default:
                    return typeof(string);
            }
        }

#if SHAREPOINT2010
        private static object GetFieldValuTaxonomy(SPListItem item, SPField field)
        {
            object value = item[field.Id];
            if (value == null) return DBNull.Value;
            try { return field.GetValidatedString(value); } catch { return value.ToString(); }
        }
#endif

        private static object GetFieldValueString(SPListItem item, SPField field)
        {
            object value = item[field.Id];
            if (value == null) return DBNull.Value;
            if (value is string) return (string)value;
            return value.ToString();
        }

        private static object GetFieldValueDouble(SPListItem item, SPField field)
        {
            object value = item[field.Id];
            return value == null ? (object)DBNull.Value : (object)Convert.ToDouble(value);
        }

        private static object GetFieldValueInt(SPListItem item, SPField field)
        {
            object value = item[field.Id];
            return value == null ? (object)DBNull.Value : (object)Convert.ToInt32(value);
        }

        private static object GetFieldValueBoolean(SPListItem item, SPField field)
        {
            object value = item[field.Id];
            return value == null ? (object)DBNull.Value : (object)Convert.ToBoolean(value);
        }

        private static object GetFieldValueDateTime(SPListItem item, SPField field)
        {
            object value = item[field.Id];
            return value == null ? (object)DBNull.Value : (object)Convert.ToDateTime(value);
        }
    }
}